#include "assitant.h"
#include "main.h"
#include "mqtts.h"
/*
CmdDef lily_cmds[Lily_cmd_len];
const char *lily_cmd_names[Lily_cmd_len];
int lily_cmds_n = 0;
typedef char *str_;
const int max_arg_n = 8;
static str_ args_list[max_arg_n];

int split_args(char dst[][32], char *str, const char *spl, int max_sub_len, int max_n)
{
  int n = 0;
  char *result = NULL;
  result = strtok(str, spl);

  while (result != NULL)
  {
    if (strlen(result) >= max_sub_len)
    {
      return -1;
    }
    strcpy(dst[n++], result);
    if (n > max_n)
    {
      return -2;
    }
    result = strtok(NULL, spl);
  }
  return n;
}

int str_split(char *str, char split_char)
{
  int _n = 0;
  if (*str == '\0')
    return _n;
  char *last; // , * next;
  char *now = str;
  if (*now != split_char)
  {
    args_list[_n++] = str;
  }
  last = now;
  now++;
  while (*now != '\0')
  {
    if (*last == split_char && *now != split_char)
    {
      args_list[_n++] = now;
      if (_n >= max_arg_n)
      {
        outs("cmd too long");
        return _n;
      }
    }
    if (*last != split_char && *now == split_char)
    {
      *now = '\0';
      last = &split_char;
      now++;
      if (_n >= max_arg_n)
      {
        outs("cmd too long");
        return _n;
      }
      continue;
    }
    last = now;
    now++;
  }
  return _n;
}

int cmd_help(int n, char *args[])
{
  int i;
  for (i = 0; i < lily_cmds_n; i++)
  {
    out_(i);
    out_(":");
    outs(lily_cmd_names[i]);
  }
  return n;
}

int do_cmd(char *cmd)
{
  int i;
  if (*cmd == '$')
  {
    char *args[2];
    args[1] = cmd + 1;
    return cmd_set(2, args);
  }
  var argn = str_split(cmd, ' ');
  if (argn == 0)
    return -1;
  String head(args_list[0]);
  for (i = 0; i < lily_cmds_n; i++)
  {
    if (head.startsWith(lily_cmd_names[i]))
    {
      int rtc = (lily_cmds[i])(argn, args_list);
      if (rtc < 0)
      {
        out_("[ERROR]:rtc=");
        outs(rtc);
      }
      return rtc;
    }
  }
  out_(cmd);
  outs(":not found");
  return -404;
}

void cmd_in(char c)
{
  const int rx_len = 128 - 1;
  static char rx[rx_len + 1];
  static int at = 0;
  if (c == '\r' || c == '\t')
    return;

  if (c == '\n' || c == ';')
  {
    rx[at] = '\0';
    do_cmd(rx);
    Serial.flush();
    at = 0;
  }
  else
    rx[at++] = c;
  if (at >= rx_len)
  {
    outs("rx buffer overflow");
    at = 0;
  }
}
*/
int __serial_echo = 0;
extern Pipe __std_in_pipe_handle;

int serial_query()
{
  static char c = 0;
  while (Serial.available() > 0)
  {
    c = Serial.read();
    if (__serial_echo)
    {
      if (c != '\b')
      {
        Serial.write(c);
      }
      else
      {
        Serial.write("\b \b");
      }
    }
    pipe_release_data(__std_in_pipe_handle, &c, 1);
  }
  return 0;
}

/*
int new_cmd(const char *name, CmdDef f)
{
  if (lily_cmds_n >= Lily_cmd_len)
  {
    xouts("overflow");
    return -1;
  }
  lily_cmd_names[lily_cmds_n] = name;
  lily_cmds[lily_cmds_n++] = f;
  return 0;
}
*/
int cmd_test(int n, char *args[])
{
  int i;
  for (i = 0; i < n; i++)
  {
    sprintf(tx, "%d:%s\n", i, args[i]);
    // out_(tx);
    mqtt_out(tx);
  }
  return n;
}
int timer_restart()
{
  ESP.deepSleep(1E6); // sleep 1s
  return 0;
}
int cmd_restart(int n, char *args[])
{
  if (n > 1)
  {
    var s = Arg(1);
    if (s == "-h")
    {
      outs("restart [after_sec]; restart after a peroid of time");
      outs("restart 0  :restart now");
      return 0;
    }

    var ok = is_int(args[1]);
    if (!ok)
    {
      outs("bad arguments");
      return -1;
    }
    var val = Arg(1).toInt();
    if (val <= 0)
    {
      ESP.deepSleep(0);
      return 0;
    }
    add_timer_once(timer_restart, Second(val));
    return 0;
  }
  ESP.reset();
  return 0;
}

bool is_int(const char *s)
{
  if (!s)
    return false;
  if (*s == '\0')
    return false;
  while (*s != '\0')
  {
    if (*s < '0' || *s > '9')
    {
      return false;
    }

    s++;
  }
  return true;
}

void sout_(const char *s)
{
  Serial.print(s);
  mqtt_out(s);
}
void sout_(const String &s)
{
  Serial.print(s);
  mqtt_out(s.c_str());
}
void sout_(const char s)
{
  Serial.print(s);
  tx_back[0] = s;
  tx_back[1] = '\0';
  mqtt_out(tx_back);
}
void sout_(const int s)
{
  Serial.print(s);
  sprintf(tx_back, "%d", s);
  mqtt_out(tx_back);
}
void sout_(const float s)
{
  Serial.print(s);
  sprintf(tx_back, "%f", s);
  mqtt_out(tx_back);
}

void souts(const char *s)
{
  Serial.println(s);
  int n = strlen(s);
  if (n < tx_len - 1)
  {
    strcpy(tx_back, s);
    tx_back[n++] = '\n';
    tx_back[n] = '\0';
    mqtt_out(tx_back);
  }
}
void souts(const String &s)
{
  souts(s.c_str());
  // Serial.println(s);
  // var sc = s + "\n";
  // mqtt_out(sc);
}
void souts(const char s)
{
  Serial.println(s);
  int i = 0;
  tx_back[i++] = s;
  tx_back[i++] = '\n';
  tx_back[i] = '\0';
  mqtt_out(tx_back);
}
void souts(const int s)
{
  Serial.println(s);
  sprintf(tx_back, "%d\n", s);
  mqtt_out(tx_back);
}
void souts(const float s)
{
  Serial.println(s);
  sprintf(tx_back, "%f\n", s);
  mqtt_out(tx_back);
}

// convert date-time to string
void str_tm(char *tx, datetime t)
{
  sprintf(tx, "%d-%d-%d %d:%d:%d",
          t->tm_year, t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
}
void str_tm(char *tx, time_t t)
{
  var now_tm = gmtime(&t);
  str_tm(tx, now_tm);
}

/* read format date-time like and only like:
  yyyy-mm-dd hh:mm:ss
  yyyy-mm-dd hh-mm-ss
  !note: do not use in a cmd when you need using args after that
  !note: in-place for  t and str
*/
int tm_from_str(datetime t, char *str)
{
  var p = str;
  int c1 = 0, c2 = 0;
  // basic check
  while (*p)
  {
    if (*p == ':')
    {
      c1++;
      if (c1 > 2)
        return -1;
      *p = '-';
    }
    else if (*p == ' ')
    {
      c2++;
      *p = '-';
    }
    else if (*p == '\n' || *p == '.')
    {
      *p = 0;
      break;
    }
    p++;
  }
  if (c1 == 1 || c2 == 0)
    return -3;
  var tokens = str_split(str, '-');
  int n = tokens->count;
  if (n != 6)
    return -4;
  int i;
  /*
  int	tm_sec;
  int	tm_min;
  int	tm_hour;
  int	tm_mday;
  int	tm_mon;
  int	tm_year;
  */
  int *ip = (int *)t;
  for (i = 0; i < n; i++)
  {
    var token = list_content(tokens, string)[i];
    int val = atoi(token);
    ip[5 - i] = val;
  }
  delete_list(tokens);
  return 0;
}
